package com.wise.transactionsyn.sample2;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Component
public class AfterCommitExecutorImpl extends TransactionSynchronizationAdapter implements AfterCommitExecutor {
    private static final Logger logger = LoggerFactory.getLogger(AfterCommitExecutorImpl.class);
    private static final ThreadLocal<List<Runnable>> runnables = new ThreadLocal();
    private ExecutorService threadPool = Executors.newFixedThreadPool(5);

    /**
     * 重写execute方法，执行前，判断事务同步器状态是否激活，否的话则先放入threadLocal暂存
     *
     * @param runnable
     */
    @Override
    public void execute(Runnable runnable) {
        logger.info("Submitting new runnable {} to run after commit", runnable);
        //如果事务同步管理器不能正常运行，为了程序的健壮性，还是将其单独将任务执行
        if (!TransactionSynchronizationManager.isSynchronizationActive()) {
            logger.info("Transaction synchronization is NOT ACTIVE. Executing right now runnable {}", runnable);
            runnable.run();
            return;
        }
        //如果事务同步管理器能够正常运行，则将任务放入threadLocal暂存，待事务提交后正常执行
        List<Runnable> threadRunnables = runnables.get();
        if (threadRunnables == null) {
            threadRunnables = new ArrayList<>();
            runnables.set(threadRunnables);
            TransactionSynchronizationManager.registerSynchronization(this);
        }
        threadRunnables.add(runnable);
    }

    /**
     * 事务提交后，将threadLocal里面存储的runnable取出全部异步执行
     */
    @Override
    public void afterCommit() {
        List<Runnable> threadRunnables = runnables.get();
        logger.info("Transaction successfully committed, executing {} runnables", threadRunnables.size());
        for (int i = 0; i < threadRunnables.size(); i++) {
            Runnable runnable = threadRunnables.get(i);
            logger.info("Executing runnable {}", runnable);
            try {
                threadPool.execute(runnable);
            } catch (Exception e) {
                logger.error("Failed to execute runnable " + runnable, e);
            }
        }
    }

    /**
     * 事务结束之后将存储于threadLocal中的所有任务清空
     *
     * @param status
     */
    @Override
    public void afterCompletion(int status) {
        logger.info("Transaction completed with status {}", status == STATUS_COMMITTED ? "COMMITTED" : "ROLLED_BACK");
        runnables.remove();
    }
}
